using Unity.Burst;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Serialization;

namespace DA.AnimGraph {

    public enum SyncTimeMode : byte {
        Time, // 绝对时间
        Normalize, // 百分比时间
    }

    /// <summary>
    /// 外部指定同步时间
    /// </summary>
    public struct InSyncTime {
        public float time;
        public SyncTimeMode syncTimeMode;
    }

    [BurstCompile]
    public static unsafe class SyncGroupProcessor {
        [BurstCompile]
        public static void Process(in UnsafeList<SyncGroup> syncGroups, in UnsafeHashMap<AUID, InSyncTime> inSyncTimes) {
            foreach (var group in syncGroups) {
                if (inSyncTimes.IsCreated && inSyncTimes.TryGetValue(group.groupID, out InSyncTime inTime)) {
                    ProcessGroupByInSync(group, inTime);
                    continue;
                }
                ProcessGroupWithoutLeader(group);
            }
        }

        /// 用最早加入的作为leader        
        [BurstCompile]
        static void ProcessGroupWithoutLeader(in SyncGroup group) {
            if (group.Count <= 1) return;

            var leaderInfo = group.SyncClipInfos[group.leaderIndex];
            var timeState = *leaderInfo.timeState;
            timeState.GetProgress(out float baseProgress, out float accuProgress);

            for (int i = 0; i < group.SyncClipInfos.Length; i++) {
                if (i != group.leaderIndex) {
                    var info = group.SyncClipInfos[i];
                    info.timeState->SetProgress(baseProgress, accuProgress);
                }
            }
        }

        /// <summary>
        /// 使用外部指定的进度
        /// </summary>
        [BurstCompile]
        static void ProcessGroupByInSync(in SyncGroup group, in InSyncTime inTime) {
            for (int i = 0; i < group.SyncClipInfos.Length; i++) {
                var info = group.SyncClipInfos[i];
                switch (inTime.syncTimeMode) {
                    case SyncTimeMode.Time:
                        info.timeState->Reset(inTime.time);
                        break;
                    case SyncTimeMode.Normalize:
                        info.timeState->SetProgress(inTime.time, 0);
                        break;
                }
            }
        }
    }
}
